package de.justphil.tcg.tcgserver.websockets.services;

import static de.justphil.tcg.tcgserver.commons.logging.TCGLogging.*;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;

import org.slf4j.Logger;


import de.justphil.tcg.tcgserver.websockets.config.WebSocketConfig;

public class NewGameMonitor {
	private static final Logger log = logger(NewGameMonitor.class);

	private final ScheduledExecutorService exec;
	private final ConcurrentMap<Long, ScheduledFuture<?>> newGames;
	private volatile OnGameExpiredListener ogeListener;
	
	public NewGameMonitor() {
		exec = Executors.newScheduledThreadPool(WebSocketConfig.NGM_THREAD_POOL_SIZE);
		newGames = new ConcurrentHashMap<Long, ScheduledFuture<?>>();
	}
	
	/* ############################################################################################ */
	/* ############################################################################################ */
	/* ############################################################################################ */
	
	public interface OnGameExpiredListener {
		public void onGameExpired(long gameId);
	}
	
	public void setOnGameExpiredListener(OnGameExpiredListener ogeListener) {
		this.ogeListener = ogeListener;
	}
	
	public void removeOnGameExpiredListener() {
		this.ogeListener = null;
	}
	
	/* ############################################################################################ */
	/* ############################################################################################ */
	/* ############################################################################################ */
	
	public void monitorNewGame(long gameId) {
		log.info("NewGameMonitor is about to start monitoring the game '{}'.", gameId);
		
		final long gId = gameId;
		
		Runnable r = new Runnable() {

			@Override
			public void run() {
				if (ogeListener != null)
					ogeListener.onGameExpired(gId);
				
				newGames.remove(gId);
			}
			
		};
		
		newGames.put(
				gameId,
				exec.schedule(r, WebSocketConfig.GAME_EXPIRATION_TIMEOUT, WebSocketConfig.GAME_EXPIRATION_TIMEOUT_UNIT)
		);
	}
	
	public void onNewGameStarted(long gameId) {
		log.info("NewGameMonitor is about to stop monitoring the game '{}'.", gameId);
		
		ScheduledFuture<?> sf = newGames.remove(gameId);
		
		if (sf != null) {
			if (sf.cancel(true)) {
				log.debug("Monitoring task for the game '{}' has been successfully canceled.", gameId);
			}
			else {
				log.debug("Monitoring task for the game '{}' couldn't be canceled.", gameId);
			}
		}
		else {
			log.debug("NewGameMonitor hasn't monitored this game anymore! ({})", gameId);
		}
	}
	
	public void onFirstPlayerJoined(long gameId) {
		cleanUp(gameId);
		monitorNewGame(gameId);
	}
	
	public void cleanUp(long gameId) {
		onNewGameStarted(gameId);
	}
}
